package com.crazy.boot.config;

import java.util.HashMap;
import java.util.LinkedHashMap;

import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.Cookie.SameSiteOptions;
import org.apache.shiro.web.servlet.ShiroHttpSession;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

import com.crazy.boot.shiro.CustomerRealm;
import com.crazy.boot.util.SessionIdMine;

/**
 * shiro配置类
 * @author CrazyCat
 */
@Configuration
public class ShiroConfig {

	/**
     * Shiro生命周期处理器
     * @return
     */
    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){
        return new LifecycleBeanPostProcessor();
    }

    /**
     * 自动创建代理
     * @return
     */
    @Bean
    @DependsOn({"lifecycleBeanPostProcessor"})
    public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){
        DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        advisorAutoProxyCreator.setProxyTargetClass(true);
        return advisorAutoProxyCreator;
    }
    
	/**
	 * 
	 * @Title: shiroFilterFactoryBean
	 * @Description: shiro过滤器配置
	 * @param 参数
	 * @return ShiroFilterFactoryBean 返回类型
	 * @author CrazyCat
	 * @date 2021年6月24日 
	 * @throws
	 */
	@Bean
	public ShiroFilterFactoryBean shiroFilterFactoryBean() {
		//创建过滤器工厂对象
		ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
		//设置核心安全管理对象
		factoryBean.setSecurityManager(this.securityManager());
		// 无登录跳转路径
		factoryBean.setLoginUrl("/index/UnLogin");
		// 无权限跳转路径
		factoryBean.setUnauthorizedUrl("/index/UnAuthorized");
		//创建权限集合
		HashMap<String, String> filterMap = new LinkedHashMap<String, String>();
		// * 第一个参数：访问路径，第二个：权限
		// * anon：没有限制都可以访问
		// * authc：必须登录后才能访问
		// * user：Remember Me使用
		// * prems：必须有相应的权限才能操作 
		// * roles：必须有相应的角色才能操作
		filterMap.put("/index/login", "anon");
		filterMap.put("/index/register", "anon");
		filterMap.put("/index/UnLogin", "anon");
		filterMap.put("/index/UnAuthorized", "anon");
		
		//filterMap.put("/user/listUser", "roles[admin]");
		
		filterMap.put("/**", "user");
		//设置过滤集合
		factoryBean.setFilterChainDefinitionMap(filterMap);
		return factoryBean;
	}

	/**
	 * 
	 * @Title: securityManager
	 * @Description: shiro核心管理对象
	 * @param 参数
	 * @return SecurityManager 返回类型
	 * @author CrazyCat
	 * @date 2021年6月24日 
	 * @throws
	 */
	@Bean
	public SecurityManager securityManager() {
		//创建安全管理对象
		DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
		//设置realm
		securityManager.setRealm(this.customerRealm());
		//设置记住我
		securityManager.setRememberMeManager(this.rememberMeManager());
		//设置session管理对象
		securityManager.setSessionManager(this.sessionManager());
		//设置缓存
		securityManager.setCacheManager(this.ehCacheManager());
		return securityManager;
	}

	/**
	 * 
	 * @Title: rememberMeCookie
	 * @Description: 记住我配置
	 * @param 参数
	 * @return SimpleCookie 返回类型
	 * @author CrazyCat
	 * @date 2021年6月24日 
	 * @throws
	 */
	@Bean
	public SimpleCookie rememberMeCookie() {
		// 设置cookie名称，对应login.html页面的<input type="checkbox" name="rememberMe"/>
		SimpleCookie cookie = new SimpleCookie("rememberMe");
		//设置cookie发送规则，Strict：不发送，Lax：部分发送（默认），none：发送
		cookie.setSameSite(SameSiteOptions.NONE);
		//是否允许js操作jsessionid
		cookie.setHttpOnly(false);
		//在SameSite为none时，发送cookie，Cookie 只能通过 HTTPS 协议发送
		cookie.setSecure(true);
		// 设置cookie的过期时间，单位为秒，这里为一天
		cookie.setMaxAge(86400);
		return cookie;
	}

	/**
	 * 
	 * @Title: rememberMeManager
	 * @Description: 记住我管理器
	 * @param 参数
	 * @return CookieRememberMeManager 返回类型
	 * @author CrazyCat
	 * @date 2021年6月24日 
	 * @throws
	 */
	@Bean
	public CookieRememberMeManager rememberMeManager() {
		CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
		cookieRememberMeManager.setCookie(this.rememberMeCookie());
		// rememberMe cookie加密的密钥 建议每个项目都不一样 默认AES算法 密钥长度(128 256 512 位)
		cookieRememberMeManager.setCipherKey(Base64.decode("2AvVhdsgUs0FSA3SDFAdag=="));
		return cookieRememberMeManager;
	}
	
	/**
	 * shiro缓存管理器;
	 * 需要添加到securityManager中
	 * @return
	 */
	@Bean
	public EhCacheManager ehCacheManager(){
	    EhCacheManager cacheManager = new EhCacheManager();
	    cacheManager.setCacheManagerConfigFile("classpath:ehcache-shiro.xml");
	    return cacheManager;
	}

	/**
	 * 
	 * @Title: sessionManager
	 * @Description: 定义session管理对象
	 * @param 参数
	 * @return SessionManager 返回类型
	 * @author CrazyCat
	 * @date 2021年6月24日 
	 * @throws
	 */
	@Bean
	public SessionManager sessionManager() {
		DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
		//设置sessionid规则
		SimpleCookie cookie = new SimpleCookie(ShiroHttpSession.DEFAULT_SESSION_ID_NAME);
		//是否允许js操作jsessionid
		cookie.setHttpOnly(false);
		//在SameSite为none时，发送cookie，Cookie 只能通过 HTTPS 协议发送
		cookie.setSecure(true);
		//设置cookie发送规则，Strict：不发送，Lax：部分发送（默认），none：发送
		cookie.setSameSite(SameSiteOptions.NONE);
		//把cookie规则设置到session管理
		sessionManager.setSessionIdCookie(cookie);
		//设置session规则
		sessionManager.setSessionDAO(this.sessionDao());
		//设置不在url中显示sessionid
		sessionManager.setSessionIdUrlRewritingEnabled(false);
		return sessionManager;
	}

	/**
	 * 
	 * @Title: sessionDao
	 * @Description: session规则配置
	 * @param 参数
	 * @return EnterpriseCacheSessionDAO 返回类型
	 * @author CrazyCat
	 * @date 2021年6月24日 
	 * @throws
	 */
	@Bean
	public EnterpriseCacheSessionDAO sessionDao() {
		EnterpriseCacheSessionDAO abstractSessionDao = new EnterpriseCacheSessionDAO();
		//自定义sessionid的生成
		abstractSessionDao.setSessionIdGenerator(new SessionIdMine());
		return abstractSessionDao;
	}

	/**
	 * 
	 * @Title: customerRealm
	 * @Description: Realm管理
	 * @param 参数
	 * @return CustomerRealm 返回类型
	 * @author CrazyCat
	 * @date 2021年6月24日 
	 * @throws
	 */
	@Bean
	public CustomerRealm customerRealm() {
		CustomerRealm realm = new CustomerRealm();
		//设置加密器凭证
		HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
		//加密算法
		matcher.setHashAlgorithmName("md5");
		//加密次数
		matcher.setHashIterations(1024);
		//把加密规则设置到realm
		realm.setCredentialsMatcher(matcher);
		/* 开启支持缓存，需要配置如下几个参数 */
		realm.setCachingEnabled(true);
	    // 启用身份验证缓存，即缓存AuthenticationInfo信息，默认false
		realm.setAuthenticationCachingEnabled(true);
	    // 缓存AuthenticationInfo信息的缓存名称 在 ehcache-shiro.xml 中有对应缓存的配置
		realm.setAuthenticationCacheName("authenticationCache");
	    // 启用授权缓存，即缓存AuthorizationInfo信息，默认false
		realm.setAuthorizationCachingEnabled(true);
	    // 缓存AuthorizationInfo 信息的缓存名称  在 ehcache-shiro.xml 中有对应缓存的配置
		realm.setAuthorizationCacheName("authorizationCache");
		return realm;
	}
	
	/**
     *  开启shiro aop注解支持.否则@RequiresRoles等注解无法生效
     *  使用代理方式;
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(this.securityManager());
        return authorizationAttributeSourceAdvisor;
    }

}
